home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-06-12 | 9.7 KB | 274 lines | [TEXT/EDIT] |
-
- ;;; Sample program for "Objects in Pearl Lisp"
- ;;; by Stephen E. Miner
- ;;; Written in Pearl Lisp 1.01
- ;;; File: Solar.lisp
- ;;; Version: 1.0
-
-
- ;;; NOTE: The "object-variable" declarations prevent the
- ;;;compiler from issuing warnings about free variables.
-
-
- ;;; Set up environment
- (eval-when (eval load compile)
- (require 'quickdraw))
- (eval-when (eval compile)
- (require 'records))
-
-
- ;;; Global variables
- (defvar *solar-num* 0 "Global counter for numbering windows.")
- (defvar *time* 0 "Global variable holding the time that is displayed.")
- (defvar *stop-flag* t "Non-nil if the simulation should stop.")
-
-
- ;;; The planet class
- (defobject *planet* nil)
-
- (defobfun (exist *planet*) (init-list)
- "Initializes an instance of the *planet* class according to
- INIT-LIST. Useful init keywords are :period, :size, :pattern,
- :radius and :center. The return value is undefined."
- (have 'period (getf init-list :period 25))
- (have 'size (getf init-list :size 3))
- (have 'pattern (getf init-list :pattern *black-pattern*))
- (have 'x 0)
- (have 'y 0)
- (have 'satellites nil)
- (let ((center (getf init-list :center))
- (me (self))) ;(self) returns the object being defined
- (have 'radius (getf init-list :radius (if center 25 0)))
- (when center
- (ask center (add-satellite me)))))
-
- (defobfun (add-satellite *planet*) (sat)
- "Add SAT to the planet's list of satellites and return the new
- list."
- (declare (object-variable satellites))
- (setq satellites (cons sat satellites)))
-
- (defobfun (update-system *planet*) (time cx cy)
- "Update the x and y coordinates of the planet according to the
- TIME and the offsets CX and CY which should be the x and y
- coordinates of the center of the planet's orbit. Then recursively
- send the update-system message to the satellites of the planet
- using the new x and y coordinates as the offsets. The return
- value is undefined."
- (declare (object-variable period radius x y satellites))
- (let* ((theta (* 2 pi (/ time period)))
- (new-x (+ cx (round (* radius (cos theta)))))
- (new-y (+ cy (round (* radius (sin theta))))))
- (setq x new-x y new-y)
- (dolist (sat satellites)
- (ask sat (update-system time new-x new-y)))))
-
-
-
- ;;; The planet objects (the numbers are not accurate, but they
- ;;; produce a reasonable display.)
-
- (defparameter *sun* (oneof *planet* :center nil :size 11
- :pattern *light-gray-pattern*))
-
- (defparameter *mercury* (oneof *planet* :radius 20 :center
- *sun* :period 12 :size 3 :pattern
- *dark-gray-pattern*))
-
- (defparameter *venus* (oneof *planet* :radius 35 :center
- *sun* :period 32 :size 5 :pattern
- *dark-gray-pattern*))
-
- (defparameter *earth* (oneof *planet* :radius 60 :center *sun*
- :period 52 :size 6 :pattern *gray-pattern*))
-
- (defparameter *moon* (oneof *planet* :radius 10 :center
- *earth* :period 4 :size 2))
-
- (defparameter *mars* (oneof *planet* :radius 85 :center *sun*
- :period 90 :size 5 :pattern *dark-gray-pattern*))
-
-
-
- ;;; The solar window class
- (defobject *solar-window* *window*)
-
- (defobfun (exist *solar-window*) (init-list)
- "Initializes an instance of the *solar-window* according to
- the INIT-LIST. Useful keywords are :center which specifies
- the gravitational center of the displayed system and :view
- which specifies the planet that controls the viewpoint of the
- display. The return value is undefined."
- (declare (object-variable center))
- (usual-exist (init-list-default init-list
- :window-title "Solar System"
- :window-size #@(250 250)
- :window-show nil))
- ;;don't show the window until the window is fully initialized
- (have 'center (getf init-list :center))
- (have 'view (getf init-list :view center))
- (center-origin)
- (window-show))
-
-
- ;;; The event system will automatically ask windows to handle
- ;;; certain events. Specialized object functions for handling
- ;;; these events are defined below.
-
- (defobfun (window-draw-contents *solar-window*) ()
- "Specialized version of window-draw-contents called by the
- event system whenever part of the window needs to be redrawn.
- The return value is undefined."
- (declare (object-variable center view x y))
- (erase-window)
- (usual-window-draw-contents)
- (draw-system center (- (ask view x)) (- (ask view y))))
-
- (defobfun (window-zoom-event-handler *solar-window*)
- (message)
- "Specialized version of window-zoom-event-handler which
- is called by the operating system when the user clicks in the
- zoom box. The MESSAGE is passed on to the
- usual-window-zoom-event-handler. This version also recenters
- the origin. The return value is undefined."
- (usual-window-zoom-event-handler message)
- (center-origin))
-
- (defobfun (set-window-size *solar-window*) (h &optional v)
- "Specialized version of set-window-size. Sets the size of the
- window according to horizontal and vertical dimensions, H and V.
- H and V are either two integers or H is taken as a point if V is nil.
- Also recenters the origin and redraws the window. Returns the
- window's new size as a point."
- (prog1
- (usual-set-window-size h v)
- (center-origin)
- (window-draw-contents)))
-
- (defobfun (center-origin *solar-window*) ()
- "Adjust the origin to the center of the window. Returns the
- window's new upper lefthand corner as a point."
- (let ((pt (window-size)))
- (set-origin (floor (point-h pt) -2)
- (floor (point-v pt) -2))))
-
- (defobfun (draw-system *solar-window*) (planet x-off y-off)
- "Draw the PLANET and its satellites in the window after adding
- X-OFF and Y-OFF to the planet's x and y coordinates. The return
- value is undefined."
- (declare (object-variable x y size pattern satellites))
- (let ((x0 (+ (ask planet x) x-off))
- (y0 (+ (ask planet y) y-off))
- (size (ask planet size)))
- ;;allocate a temporary rectangle for graphics calls
- (rlet ((rec :rect :top (- x0 size) :left (- y0 size)
- :bottom (+ x0 size) :right (+ y0 size)))
- (fill-oval (ask planet pattern) rec)
- (frame-oval rec)))
- ;;draw the satellites
- (dolist (sat (ask planet satellites))
- (draw-system sat x-off y-off)))
-
- (defobfun (erase-window *solar-window*) ()
- "Erase the contents of the window. The return value is
- undefined."
- ;;rref access the Macintosh record and in this case returns
- ;; the window's portrect. See the Pearl Lisp documentation
- ;; for more information about records.
- (declare (object-variable wptr))
- (erase-rect (rref wptr window.portrect)))
-
-
- ;;; Menu action functions
-
- (defun new-solar (view-planet title)
- "Create a new solar window with VIEW-PLANET determining the
- point of view and the TITLE string used as base for the window
- title. The global *solar-num* is incremented and appended to the
- window title to ease identification. Returns the new window object."
- (setq *solar-num* (+ *solar-num* 1))
- (oneof *solar-window* :window-title
- (format nil "~A ~A" title *solar-num*)
- :center *sun*
- :view view-planet))
-
- (defun exit-solar ()
- "Close all the solar windows and deinstall the menu. The return
- value is undefined."
- (dolist (w (windows *solar-window*))
- (ask w (window-close)))
- (ask *solar-menu* (menu-deinstall)))
-
- (defun run-loop ()
- "Run the simulation until the global *stop-flag* is true. This
- function also manages the solar menu."
- (setq *stop-flag* nil)
- (ask *stop-item* (set-menu-item-check-mark nil))
- (ask *run-item* (set-menu-item-check-mark t))
- (loop
- (let ((wlist (windows *solar-window*)))
- ;;list of all *solar-window*'s
- (when (or *stop-flag* (null wlist))
- ;;check for end of simulation
- (ask *run-item* (set-menu-item-check-mark nil))
- (ask *stop-item* (set-menu-item-check-mark t))
- (return))
- (setq *time* (+ 1 *time*))
- (ask *sun* (update-system *time* 0 0))
- ;;updates all the x and y coords
- (dolist (w wlist)
- (ask w (when (ownp 'wptr) ;protect against close-box
- (window-draw-contents))))))) ;redraw the window
-
-
- ;;; The menu items
-
- (defparameter *new-helio-item*
- (oneof *menu-item* :menu-item-title "New Helio"
- :menu-item-action '(new-solar *sun* "Heliocentric")))
-
- (defparameter *new-geo-item*
- (oneof *menu-item* :menu-item-title "New Geo"
- :menu-item-action '(new-solar *earth* "Geocentric")))
-
- (defparameter *new-luna-item*
- (oneof *menu-item* :menu-item-title "New Luna"
- :menu-item-action '(new-solar *moon* "Lunacentric")))
-
- (defparameter *run-item*
- (oneof *menu-item* :menu-item-title "Run"
- :menu-item-action '(when *stop-flag*
- (eval-enqueue '(run-loop)))))
-
- (defparameter *stop-item*
- (oneof *menu-item* :menu-item-title "Stop"
- :menu-item-action '(setq *stop-flag* t)))
-
- (defparameter *exit-item*
- (oneof *menu-item* :menu-item-title "Exit"
- :menu-item-action
- '(progn
- (setq *stop-flag* t)
- (eval-enqueue '(exit-solar)))))
- ;;The eval-enqueue makes sure that we wait for the run-loop to
- ;; finish before we exit.
-
- (defparameter *solar-menu*
- (oneof *menu* :menu-title "Solar"
- :menu-items (list *new-helio-item*
- *new-geo-item*
- *new-luna-item*
- (oneof *menu-item* :menu-item-title "-"
- :disabled t)
- *run-item*
- *stop-item*
- *exit-item*)))
-
-
- ;;; Install the menu
- (ask *run-item* (set-menu-item-check-mark (not *stop-flag*)))
- (ask *stop-item* (set-menu-item-check-mark *stop-flag*))
- (ask *solar-menu* (menu-install))
-
-
-